package com.hhck.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.hhck.entity.CurrentUser;
import com.hhck.exception.BusinessException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * token工具类
 */
@Component
public class TokenUtils {

    // 注入redis模板
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    // 注入配置文件中的warehouse.expire-time属性 -- token的过期时间
    @Value("${token.expire-time}")
    private int expireTime;

    // token中存放用户id对应的名字
    private static final String CLAIM_NAME_USERID = "CLAIM_NAME_USERID";
    // token中存放用户对应的账号
    private static final String CLAIM_NAME_USERCODE = "CLAIM_NAME_USERCODE";
    // token中存放用户对应的名称
    private static final String CLAIM_NAME_USERNAME = "CLAIM_NAME_USERNAME";

    /**
     * 生成token的具体实现方法
     * @param currentUser  当前用户
     * @param securityKey  密钥
     */
    private String sign(CurrentUser currentUser, String securityKey){

        String token = JWT.create()
                .withClaim(CLAIM_NAME_USERID, currentUser.getUserId())      // 存放用户id
                .withClaim(CLAIM_NAME_USERCODE, currentUser.getUserCode())  // 存放用户账号
                .withClaim(CLAIM_NAME_USERNAME, currentUser.getUserName())  // 存放用户名称
                .withIssuedAt(new Date())   // 发行时间
                .withExpiresAt(new Date(System.currentTimeMillis() + expireTime))  // 有效时间
                .sign(Algorithm.HMAC256(securityKey));  // 指定密钥
        return token;
    }

    /**
     * 将当前用户信息以用户密码为密钥生成token的方法
     */
    public String loginSign(CurrentUser currentUser, String password){

        // 生成token
        String token = sign(currentUser, password);
        // 将token保存到redis中，并设置token在redis中的过期时间
        stringRedisTemplate.opsForValue().set(token, token, expireTime, TimeUnit.SECONDS);

        return token;
    }

    /**
     * 通过token获取用户信息的方法
     */
    public CurrentUser getCurrentUser(String token) {

        if(StringUtils.isEmpty(token)){
            throw new BusinessException("令牌为空，请登录！");
        }

        // 对token进行解码，获取解码后的token
        DecodedJWT decodedJWT = null;
        try {
            // 解码token
            decodedJWT = JWT.decode(token);
        } catch (JWTDecodeException e) {
            throw new BusinessException("令牌格式错误，请登录！");
        }

        // 从解码后的token中获取用户信息并封装到CurrentUser对象中返回
        int userId = decodedJWT.getClaim(CLAIM_NAME_USERID).asInt();            // 用户id
        String userCode = decodedJWT.getClaim(CLAIM_NAME_USERCODE).asString();  // 用户账号
        String userName = decodedJWT.getClaim(CLAIM_NAME_USERNAME).asString();  // 用户名称

        // 判断用户信息是否合法
        if(StringUtils.isEmpty(userCode) || StringUtils.isEmpty(userName)){
            throw new BusinessException("令牌缺失用户信息，请登录！");
        }

        return new CurrentUser(userId, userCode, userName);
    }

}

